<template>
  <div class="chat flex h-[100vh] max-md:flex-col">
    <div class="left w-[250px] max-md:w-full">
      <div
        class="user-list h-[100vh] bg-[#e7e8e9] overflow-auto max-md:h-[40vh]"
      >
        <template v-if="comUsers.length">
          <div
            class="item bg-[#e7e8e9] h-[64px] p-[15px] flex items-center justify-between cursor-pointer hover:bg-[#c9c8c8] bottom-[1px] border-b-[1px] border-[#ccc]"
            :class="{
              'bg-[#c9c8c8]': current?.userId === item.userId
            }"
            v-for="item in comUsers"
            :key="item.userId"
            @click="select(item)"
          >
            <div class="left flex items-center">
              <div
                class="avatar mr-[10px] w-[40px] h-[40px] bg-black flex items-center justify-center text-white font-bold text-[20px]"
              >
                {{ item.username[0] }}
              </div>
              <div
                class="name text-black font-bold text-[14px] flex items-center"
              >
                {{ item.username }}
                <span v-if="item.username === username">(myself)</span>
                <el-icon color="green" class="ml-[10px]" v-if="item.onLine"
                  ><CircleCheckFilled
                /></el-icon>
              </div>
            </div>
            <el-icon color="#e75e58" v-if="item.notRead"
              ><WarningFilled
            /></el-icon>
          </div>
        </template>
        <div class="flex justify-center items-center h-full" v-else>
          <el-empty description="暂无数据" />
        </div>
      </div>
    </div>
    <div
      class="right flex-1 bg-[#f5f5f5] flex flex-col h-[100vh] max-md:h-[60vh]"
      v-if="current"
    >
      <p
        class="name font-bold leading-[50px] border-b border-b-[#e7e7e7] pl-[20px] mb-[20px] h-[50px] flex-shrink-0"
      >
        {{ current.username }}
      </p>
      <div class="message-list flex-1 overflow-auto" ref="messageListRef">
        <div
          class="item flex mb-[10px]"
          :class="{ 'flex-row-reverse': item.username === username }"
          v-for="(item, index) in current.message"
          :key="index"
        >
          <div
            class="avatar mx-[20px] w-[40px] h-[40px] bg-black flex items-center justify-center text-white font-bold text-[20px] flex-shrink-0"
          >
            {{ item.username[0] }}
          </div>
          <div class="right max-w-[70%]">
            <p class="name text-[#b2b2b2] text-[14px]">{{ item.username }}</p>
            <div class="leading-9 px-4 bg-[#ffffff] text-[14px] message">
              <p v-html="item.message" />
            </div>
          </div>
        </div>
      </div>
      <div class="replay px-[20px] flex items-end pb-[20px] mt-[20px]">
        <Editor v-model="message" @keydown="handleKeyDown" height="200px" />
        <el-button type="primary" @click="send">发送</el-button>
        <el-button type="primary" :icon="PhoneFilled" @click="call"
          >call</el-button
        >
      </div>
    </div>
    <div class="flex justify-center items-center w-full" v-else>
      <el-empty description="请选择联系人" />
    </div>
    <el-dialog
      v-model="dialogVisible"
      title="登录"
      width="50%"
      :show-close="false"
      :close-on-click-modal="false"
      :close-on-press-escape="false"
    >
      <el-input v-model="username" />
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submit"> 登录 </el-button>
        </div>
      </template>
    </el-dialog>
    <el-dialog v-model="callDialogVisible" title="视频通话" width="60%">
      <div class="dialog-content flex items-center justify-between w-full">
        <div class="left flex-1 mr-4 flex items-center flex-col">
          <video id="local" />
          <p class="mt-2">mySelf</p>
        </div>
        <div class="right flex-1 flex flex-col items-center">
          <video id="remote" />
          <p class="mt-2">other side</p>
        </div>
      </div>
      <template #footer>
        <div class="dialog-footer">
          <el-button
            @click="hangUp"
            v-if="isCreateCall"
            type="danger"
            :icon="PhoneFilled"
            >挂断</el-button
          >
          <el-button type="primary" PhoneFilled @click="connect" v-else
            >接通</el-button
          >
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { socketUrl } from "@/api/config";
import {
  WarningFilled,
  CircleCheckFilled,
  PhoneFilled
} from "@element-plus/icons-vue";
import { ElMessage } from "element-plus";
import { io } from "socket.io-client";
import { computed, nextTick, onMounted, ref } from "vue";
import Editor from "@/components/Editor/index.vue";
import { useLiveKit } from "./utils/useLiveKit";
interface UserItem {
  userId: string;
  username: string;
  onLine: boolean;
  message: { userId: string; message: string; username: string }[];
  notRead: boolean;
}
const subscribeCallback = () => {
  isCreateCall.value = true;
};
const disconnectedCallBack = () => {
  callDialogVisible.value = false;
};
const { createTrack, publish, leaveRoom, join } = useLiveKit(
  subscribeCallback,
  disconnectedCallBack
);
const dialogVisible = ref(true);
const submit = () => {
  socket.auth = { username: username.value };
  socket.connect();
  dialogVisible.value = false;
};
const username = ref("");
const messageListRef = ref(null);
const socket = io(socketUrl, {
  auth: {
    username: username.value
  },
  autoConnect: false
});
socket.on("connect", () => {
  console.log("connect");
});
onMounted(() => {
  const userInfo = JSON.parse(localStorage.getItem("chatUserInfo"));
  if (userInfo) {
    username.value = userInfo.username;
    socket.auth = { userId: userInfo.userId, username: userInfo.username };
    socket.connect();
    dialogVisible.value = false;
  } else {
    dialogVisible.value = true;
  }
});
// 选中
const current = ref<UserItem | null>(null);
const select = (item: UserItem) => {
  current.value = item;
  current.value.notRead = false;
  nextTick(() => {
    if (current.value) {
      const element = messageListRef.value as HTMLElement;
      element.scrollTo({
        top: element.scrollHeight,
        left: 0,
        behavior: "smooth"
      });
    }
  });
};
const users = ref<UserItem[]>([]);
// 用户列表
socket.on("users", data => {
  data.forEach(user => {
    const res = users.value.find(item => item.userId === user.userId);
    if (res) {
      res.onLine = user.onLine;
    } else {
      users.value.push({
        ...user,
        message: [],
        notRead: false
      });
    }
  });
});
const comUsers = computed(() => {
  return users.value
    .filter(el => el.username !== username.value)
    .sort((a, b) => Number(b.onLine) - Number(a.onLine));
});
// socket连接错误
socket.on("connect_error", error => {
  if (error.message === "invalid userId") {
    localStorage.removeItem("chatUserInfo");
    dialogVisible.value = true;
    return;
  }
  if (error.message === "invalid username") {
    ElMessage.error("用户名已存在");
    username.value = "";
    dialogVisible.value = true;
    return;
  }
  ElMessage.error(error.message);
});
// 存储用户信息
socket.on("session", ({ userId, username }) => {
  socket.auth = { userId };
  localStorage.setItem("chatUserInfo", JSON.stringify({ userId, username }));
});
// 接收消息
socket.on("receive-message", ({ message, userId, username, toId }) => {
  // 提示
  const warningCurrent = users.value.find(item => item.userId === userId);
  warningCurrent.notRead = true;
  users.value.forEach(el => {
    if (el.userId === toId || el.userId === userId) {
      el.message.push({ message, userId, username });
    }
  });
  nextTick(() => {
    if (current.value) {
      const element = messageListRef.value as HTMLElement;
      element.scrollTo({
        top: element.scrollHeight,
        left: 0,
        behavior: "smooth"
      });
    }
  });
});
// call
const callDialogVisible = ref(false);
const isCreateCall = ref(true);
// 发起通话
socket.on("createCall", async ({ token }) => {
  await join(token);
  isCreateCall.value = true;
  await createTrack();
  publish();
});
// 接受通话
let receiveToken: string;
socket.on("join", async ({ token }) => {
  callDialogVisible.value = true;
  receiveToken = token;
  isCreateCall.value = false;
  createTrack();
});

const call = () => {
  callDialogVisible.value = true;
  socket.emit("call", { toId: current.value.userId });
};

// 发送消息
const message = ref("");
const send = () => {
  if (!message.value) {
    ElMessage.error("请输入消息");
    return;
  }
  socket.emit("send-message", {
    toId: current.value.userId,
    message: message.value
  });
  message.value = "";
};
const handleKeyDown = event => {
  if (event.key === "Enter" && !event.shiftKey) {
    event.preventDefault();
    send();
  }
};

// 挂断
const hangUp = async () => {
  await leaveRoom();
  receiveToken = "";
  callDialogVisible.value = false;
};
// 接通
const connect = async () => {
  await join(receiveToken);
  publish();
};
</script>
<style lang="scss" scope>
.message {
  overflow: hidden; /* 这个参数根据需要来绝对要不要 */
  word-break: break-all;
  word-wrap: break-word;
}

video {
  width: 100%;
  height: auto;
}
</style>
